<?php
namespace App\Services;

use App\Logic\LogLogic;
use Illuminate\Http\Client\RequestException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Ramsey\Uuid\Uuid;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Redis;
class DaHuangService {

    /**
     * @notes 获取唯一UUID
     * @return string
     * @author Evil丿
     * @date 2024/03/28 11:01
     */
    private static function getRequestId()
    {
        $data = Uuid::uuid1(time());
        return $data->getHex()->toString();
    }

    /**
     * @notes 获取请求token
     * @param $appId
     * @param $appSecret
     * @return mixed
     * @throws RequestException
     * @author Evil丿
     * @date 2024/06/06 15:33
     */
    private static function getRequestToken($appId, $appSecret)
    {
        $token = Redis::get('dhe:request_token');

        if($token) return $token;

        $path = '/web/open/app/auth/v1';

        $params = [
            'appId'     => $appId,
            'appSecret' => $appSecret
        ];

        $data = [
            'reqId'         => self::getRequestId(),
            'reqData'       => $params,
            'timestamp'     => time(),
            'version'       => 'v1.0',
            'signType'      => 'HMAC-SHA256',
            'appId'         => $appId
        ];

        $res = self::commonRequest($path, $data);

        $token = $res['accessToken'];

        Redis::setex('dhe:request_token', 60*60*24, $token);

        return $token;
    }

    /**
     * @notes 发起公共请求
     * @param $path
     * @param $data
     * @param $header
     * @return mixed
     * @throws RequestException
     * @author Evil丿
     * @date 2024/06/06 15:33
     */
    private static function commonRequest($path, $data, $header = [])
    {
        if(strpos($path, 'http') === false) {
            $host = config('services.dhe.host');

            $url = $host . $path;
        } else {
            $url = $path;
        }

        $response = Http::retry(3, 1000)
            -> timeout(3)
            -> withHeaders($header)
            -> post($url, $data)
            -> throw()
            -> json();

        if(!$response) {
            throw new AccessDeniedHttpException('DHE服务请求失败');
        }

        if(!$response['isSuccess'] || $response['code'] != 200) {
            throw new AccessDeniedHttpException($response['message']);
        }

        LogLogic::setDheLogs($data['reqId'], $path, $data);

        if(!$response['content']) {
            $response['content'] = $response['code'];
        }

        return $response['content'];
    }

    /**
     * @notes 生成签名字符串
     * @param $params
     * @param $appSecret
     * @return string
     * @author Evil丿
     * @date 2024/06/06 15:33
     */
    public static function makeSign($params, $appSecret)
    {
        if(key_exists('sign', $params)) unset($params['sign']);

        $data = $params['reqData'];

        uksort($params, function ($a, $b) {
            return strcoll($a, $b);
        });

        $params['signSecret'] = $appSecret;

        $params['reqData'] = json_encode($data);

        $sign_str = '';

        foreach($params as $k => $v) {
            $sign_str .= $k.'='.$v.'&';
        }

        return strtoupper(base64_encode(hash_hmac('SHA256', trim($sign_str, '&'), $appSecret, true)));
    }

    public static function checkSign($params) {
        $appSecret = config('services.dhe.appSecret');

        $request_sign = $params['sign'];

        if(key_exists('sign', $params)) unset($params['sign']);

        $data = $params['reqData'];

        uksort($params, function ($a, $b) {
            return strcoll($a, $b);
        });

        $params['signSecret'] = $appSecret;

        $params['reqData'] = stripslashes(json_encode($data, 256));

        $sign_str = '';

        foreach($params as $k => $v) {
            $sign_str .= $k.'='.$v.'&';
        }

        $sign = strtoupper(base64_encode(hash_hmac('SHA256', trim($sign_str, '&'), $appSecret, true)));

        return $sign === $request_sign;
    }

    /**
     * @notes Api文档接口请求
     * @param $path
     * @param $params
     * @return mixed
     * @throws \Illuminate\Http\Client\RequestException
     * @author Evil丿
     * @date 2024/03/28 11:23
     */
    private static function apiRequest($path, $params)
    {
        $appId = config('services.dhe.appId');

        $appSecret = config('services.dhe.appSecret');

        $header = [
            'Dahuange-User-Access-Token' => self::getRequestToken($appId, $appSecret)
        ];

        $data = [
            'reqId'         => self::getRequestId(),
            'reqData'       => $params,
            'timestamp'     => time(),
            'version'       => 'v1.0',
            'signType'      => 'HMAC-SHA256',
            'appId'         => $appId
        ];

        $data['sign'] = self::makeSign($data, $appSecret);

        return self::commonRequest($path, $data, $header);
    }

    public static function formatAttach($params)
    {
        $arr = explode(',', $params['attach']);

        $device_code = "";

        foreach($arr as $v) {
            $str = explode(':', $v);

            if($str[0] == 'S') {
                $device_code = $str[1];
            }
        }

        $params['device_code'] = $device_code;

        return $params;
    }

    /**
     * @notes 请求设备开门
     * @param $device_code
     * @param $user_id
     * @param $phone
     * @param $balance
     * @param $door_num
     * @return boolean
     * @throws \Illuminate\Http\Client\RequestException
     * @author Evil丿
     * @date 2024/03/29 16:34
     */
    public static function openDoor($device_code, $user_id, $phone, $balance = 0, $door_num = "")
    {
        $params = [
            "deviceCode" => $device_code,
            "openId"     => $user_id,
            "phone"      => $phone,
            "balance"    => $balance
        ];


        if(in_array($door_num, [1,2])) {
            $params['doorNum'] = $door_num;
        }

        $path = '/web/open/machine/door/v1/open';

        $res = self::apiRequest($path, $params);

        if(!$res['doorStatus']) {
            return false;
        }

        return true;
    }

    /**
     * @notes 获取设备内商品
     * @param $device_code
     * @return mixed
     * @throws RequestException
     * @author Evil丿
     * @date 2024/06/06 15:35
     */
    public static function getDoorGoods($device_code)
    {
        $params = [
            "deviceCode" => $device_code
        ];

        $path = '/web/open/machine/goods/v1/display';

        $res = self::apiRequest($path, $params);

        return $res;
    }

    /**
     * @notes 订单支付成功回调
     * @param $url
     * @param $order_id
     * @param $trade_no
     * @param $status
     * @param $amount
     * @param $user_id
     * @param $attach
     * @param $pay_time
     * @return mixed
     * @throws RequestException
     * @author Evil丿
     * @date 2024/06/06 15:35
     */
    public static function orderRefund($url, $order_id, $trade_no, $status, $amount, $user_id, $attach, $pay_time)
    {

        $params = [
            "tradeNo"       => $order_id,
            "outTradeNo"    => $trade_no,
            "orderStatus"   => $status,
            "totalAmount"   => $amount,
            "memberNo"      => $user_id,
            "attach"        => $attach,
            "paidTime"      => $pay_time
        ];

        $res = self::apiRequest($url, $params);

        return $res;
    }

    /**
     * @notes 检查设备当前状态
     * @param $device_code
     * @return mixed
     * @throws RequestException
     * @author Evil丿
     * @date 2024/06/06 15:36
     */
    public static function doorCheck($device_code)
    {
        $params = [
            "deviceCode" => $device_code
        ];

        $path = '/web/open/machine/door/v1/open/check';

        $res = self::apiRequest($path, $params);

        return $res;
    }
}
